﻿// Would like a plugin where you enumerate a file name and a maximum age in hours.   
// If the age limit is exceeded or the file does not exist report as failure.

namespace Wolfpack.Contrib.Checks.FileDueDates
{
    using System;
    using System.Globalization;
    using System.IO;
    using Core;
    using Core.Interfaces;
    using Core.Interfaces.Entities;

    public class FileDueDateConfig : PluginConfigBase
    {
        public string DirectoryPath { get; set; }

        // 24 hour clock
        public string DueTime { get; set; }

        public string FutureInterval { get; set; }

        public string IncludeSubDirectories { get; set; }

        public string PastInterval { get; set; }

        public string SearchPattern { get; set; }
    }

    public class FileDueDate : IHealthCheckPlugin
    {
        /// <summary>
        /// default ctor
        /// </summary>
        public FileDueDate(FileDueDateConfig config)
        {
            MyIdentity = new PluginDescriptor
                           {
                               Description =
                                   string.Format(
                                       "Reports if files in, '{0},' matching the search pattern of, '{1},' have a modified timestamp before, '{2}' and within the last '{3}' hours.",
                                       config.DirectoryPath,
                                       config.SearchPattern,
                                       config.DueTime,
                                       config.PastInterval),
                               TypeId = new Guid("9A781129-66AD-4fb3-8F0D-0702731160EA"),
                               Name = config.FriendlyId
                           };

            MyConfig = config;
        }

        public FileDueDateConfig MyConfig { get; set; }

        public PluginDescriptor MyIdentity { get; set; }

        public Status Status { get; set; }

        public PluginDescriptor Identity
        {
            get { return MyIdentity; }
        }

        public void Initialise()
        {
            // do nothing
        }

        public void Execute()
        {
            CheckFiles();
        }

        private void CheckFiles()
        {
            var dueTime = DateTime.Parse(MyConfig.DueTime);
            var futureTime = dueTime.AddMinutes(int.Parse(MyConfig.FutureInterval ?? "0"));
            var pastTime = dueTime.AddMinutes(-int.Parse(MyConfig.PastInterval));

            if (DateTime.Now < dueTime)
            {
                return;
            }

            try
            {
                if (DateTime.Now <= futureTime)
                {
                    var di = new DirectoryInfo(MyConfig.DirectoryPath);
                    if (!di.Exists)
                    {
                        Publish();
                        return;
                    }

                    var fi = di.GetFiles(
                        MyConfig.SearchPattern,
                        "1" == MyConfig.IncludeSubDirectories
                            ? SearchOption.AllDirectories
                            : SearchOption.TopDirectoryOnly);

                    if (fi.Length < 1)
                    {
                        Publish();
                        return;
                    }

                    foreach (var f in fi)
                    {
                        // if last write time is less than due time and greater than now - interval
                        if (f.LastWriteTime > pastTime)
                        {
                            continue;
                        }

                        Publish(f, pastTime, dueTime);
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Debug("Unable to iterate files, {0}.", e.InnerException.Message);
            }

            Logger.Debug("Done checking FileDueDate");
        }

        private void Publish(FileSystemInfo f, DateTime minTime, DateTime maxTime)
        {
            Logger.Debug("Publishing.");
            HealthCheckData result = new HealthCheckData
            {
                Identity = Identity,
                Info =
                    string.Format(
                        "File '{0}' has write time of '{1}'. This is not greater than '{2}' and less than '{3}'.",
                        f.FullName,
                        f.LastWriteTime,
                minTime,
                maxTime),
                Result = false,
                Properties = new ResultProperties
                                 {
                                     { "Interval in Hours", MyConfig.PastInterval },
                                     { "Due Time", MyConfig.DueTime },
                                     { "Search Pattern", MyConfig.SearchPattern },
                                     { "Directory Path", MyConfig.DirectoryPath },
                                     { "Include Subdirectories", MyConfig.IncludeSubDirectories },
                                     { "File Last Write Time", f.LastWriteTime.ToString(CultureInfo.CurrentCulture) }
                                 }
            };

            Messenger.Publish(result);
        }

        private void Publish()
        {
            Logger.Debug("Publishing.");
            var result = new HealthCheckData
            {
                Identity = Identity,
                Info = "0 files match the search pattern",
                Result = false,
                Properties = new ResultProperties
                                 {
                                     { "Interval in Hours", MyConfig.PastInterval },
                                     { "Due Time", MyConfig.DueTime },
                                     { "Search Pattern", MyConfig.SearchPattern },
                                     { "Directory Path", MyConfig.DirectoryPath },
                                     { "Include Subdirectories", MyConfig.IncludeSubDirectories },
                                 }
            };

            Messenger.Publish(result);
        }
    }
}